﻿namespace ExcelTool{
    using System.Collections.Generic;
    using System.Text;
    using System.Xml;
    using System.Xml.Serialization;
    [XmlRoot("metalib")]
    public class XmlMetalib{
        #region 序列化字段
        [XmlAttribute(XML_ATTR_NAME.NAME)]
        public string lib_name;
        [XmlAttribute(XML_ATTR_NAME.DESC)]
        public string desc;
        [XmlElement(XML_ELEMENTS_NAME.CONST, IsNullable = false)]
        public List<XmlConst> const_config = new List<XmlConst>();
        [XmlElement(XML_ELEMENTS_NAME.ENUM, IsNullable = false)]
        public List<XmlEnumSet> enum_config = new List<XmlEnumSet>();
        [XmlElement(XML_ELEMENTS_NAME.GROUP, IsNullable = false)]
        public List<XmlGroupSet> group_config= new List<XmlGroupSet>();
        [XmlElement(XML_ELEMENTS_NAME.SUBCLASS, IsNullable = false)]
        public List<XmlSubClassSet> subclass_config = new List<XmlSubClassSet>();
        [XmlElement(XML_ELEMENTS_NAME.CLASS, IsNullable = false)]
        public List<XmlClassSet> class_config = new List<XmlClassSet>();
        [XmlElement(XML_ELEMENTS_NAME.VALID, IsNullable = false)]
        public XmlValidSet valid_config;
        #endregion


        #region 数据重组
        [XmlIgnore]
        public bool common = false;
        [XmlIgnore]
        private Dictionary<string, XmlBaseSet> m_referenceSets = new Dictionary<string, XmlBaseSet>();
        [XmlIgnore]
        public Dictionary<string, XmlBaseSet> ReferenceSets
        {
            get { return m_referenceSets; }
        }
        #endregion
        public bool TryGetConstValue(string const_key, out int value) {
            foreach(XmlConst const_it in const_config) {
                if(const_it.name == const_key) {
                    value = const_it.value;
                    return true; 
                }
            }
            value = -1;
            return false;
        }
        public bool CheckAndAssemble(bool common_use) {
            Reporter.SetMetalibProgress(lib_name);

            common = common_use;

            //先载入Valid配置
            if(valid_config != null && !valid_config.CheckAndAssemble(this)) return false;

            if(!common_use) {
                foreach(XmlClassSet csit in class_config) {
                    if(!csit.CheckAndAssemble(this)) return false;
                }
            }
            else if(class_config.Count > 0){
                StringBuilder error_sb = new StringBuilder();
                foreach(XmlClassSet csit in class_config) {
                    error_sb.AppendFormat("{0} |", csit.name);
                }
                Reporter.PushError("共用枚举中定义了class : {0}", error_sb.ToString());
                return false;
            }
            foreach(XmlEnumSet enumit in enum_config) {
                if(!enumit.CheckAndAssemble(this)) return false;
                m_referenceSets.Add(enumit.name, enumit);
            }
            foreach(XmlSubClassSet scsit in subclass_config) {
                if(!scsit.CheckAndAssemble(this)) return false;
                m_referenceSets.Add(scsit.name, scsit);
            }
            foreach(XmlGroupSet gset in group_config) {
                if(!gset.CheckAndAssemble(this)) return false;
                m_referenceSets.Add(gset.name, gset);
            }


            Reporter.ParseFinish();
            return true;
        }

        public bool IfClassSetExists(string class_name) {
            foreach(XmlClassSet csit in class_config) {
                if(csit.name == class_name) {
                    return true;
                }
            }

            return false;
        }
        public XmlClassSet GetClassSet(string className) {
            foreach(XmlClassSet csit in class_config) {
                if(csit.name == className) {
                    return csit;
                }
            }

            return null;
        }

        public XmlMetalib() { }
    }

    #region 辅助字段
    public class XmlConst {
        [XmlAttribute(XML_ATTR_NAME.NAME)]
        public string name;
        [XmlAttribute(XML_ATTR_NAME.VALUE)]
        public int value;
        [XmlAttribute(XML_ATTR_NAME.KEY)]
        public int key;
    }

    public class XmlDataSource {
        [XmlAttribute(XML_ATTR_NAME.TBNAME)]
        public string tablename;

        public void FormatName() {
            tablename = tablename.Replace("\\", "/");
        }
    }
    #endregion

    #region Set结构
    public abstract class XmlBaseSet {
        [XmlAttribute(XML_ATTR_NAME.NAME)]
        public string name;
        [XmlAttribute(XML_ATTR_NAME.DESC)]
        public string desc;
        [XmlAttribute(XML_ATTR_NAME.KEY)]
        public string key;
        [XmlAttribute(XML_ATTR_NAME.MODE)]
        public string mode_str;
        [XmlElement]
        public string type;

        [XmlIgnore]
        public XmlMetalib ParentLib;
        [XmlIgnore]
        public JSON_MODE mode = JSON_MODE.COMMON;

        protected bool CheckReplication(string key, ref List<string> cache, string log_str) {
            if(cache.Contains(key)) {
                Reporter.PushError(log_str, key);
                cache.Clear();
                return false;
            }

            cache.Add(key);
            return true;
        }  
        public virtual bool CheckAndAssemble(XmlMetalib _p) {
            if(mode_str == "client") {
                mode = JSON_MODE.CLIENT;
            }
            else if(mode_str == "server"){
                mode = JSON_MODE.SERVER;
            }
            Reporter.SetSetProgress(name);
            ParentLib = _p;
            return true;
        }
    }

    public class XmlBaseRefer : XmlBaseSet {
        [XmlElement(XML_ELEMENTS_NAME.ENTRY)]
        public List<XmlFieldEntry> fieldCfg;

        [XmlIgnore]
        protected int primary_idx = -1;
        [XmlIgnore]
        public int client_count = 0;
        public int server_count = 0;

        public override bool CheckAndAssemble(XmlMetalib parentLib) {
            if(!base.CheckAndAssemble(parentLib)) return false;

            List<string> name_repliaction = new List<string>();
            List<string> key_repliaction = new List<string>();

            foreach(XmlFieldEntry fe_it in fieldCfg) {
                Reporter.SetEntryProgress(fe_it.name);

                if(!CheckReplication(fe_it.name, ref name_repliaction, "xml文件：name名重复！{0}")) return false;
                if(!CheckReplication(fe_it.key, ref key_repliaction, "xml文件：key名重复！{0}")) return false;

                if(!fe_it.CheckAndAssemble(this)) return false;
                if(fe_it.Primary) {
                    if(primary_idx >= 0) {
                        Reporter.PushError("同一个结构体中定义了多条Primary数据！");
                        return false;
                    }
                    if(!XML_DATA_TYPE_NAME.PrimaryKeyType(fe_it.type)) {
                        Reporter.PushError("类型{0}不能作为主键, 请使用int、string或enum类型作为主键", fe_it.type);
                        return false;
                    }
                    primary_idx = fieldCfg.Count; 
                }
                if(fe_it.mode == JSON_MODE.CLIENT || fe_it.mode == JSON_MODE.COMMON) {
                    client_count++;
                }
                if(fe_it.mode == JSON_MODE.SERVER|| fe_it.mode == JSON_MODE.COMMON) {
                    server_count++;
                }
            }
            if(primary_idx == -1 && type == XML_DATA_TYPE_NAME.CLASS) {
                Reporter.PushError("必须在Class元素中定义一条含有primary属性的Entry作为主键!");
                return false;
            }
            if(primary_idx >= 0 && type != XML_DATA_TYPE_NAME.CLASS) {
                Reporter.PushError("检测到在非Class元素中含有primary属性的Entry，该primary属性将不会生效，请去除！");
                return false;
            }
           return true;
        }

    }
    public class XmlEnumSet : XmlBaseSet {
        [XmlElement("entry")]
        public List<XmlEnumEntry> EntryList;
        [XmlIgnore]
        public static readonly int INVALID_VALUE = int.MinValue;
        public override bool CheckAndAssemble(XmlMetalib _p) {
            if(!base.CheckAndAssemble(_p)) return false;

            List<string> name_repliaction = new List<string>();
            List<string> key_repliaction = new List<string>();
            foreach(XmlEnumEntry eit in EntryList) {

                if(!CheckReplication(eit.name, ref name_repliaction, "xml文件：name名重复！{0}")) return false;
                if(!CheckReplication(eit.key, ref key_repliaction, "xml文件：key名重复！{0}")) return false;

                if(!eit.CheckAndAssemble(this)) return false;
            }

            return true;
        }
        public int GetEnumValue(string enum_entry_key) {
            foreach(XmlEnumEntry entry in EntryList) {
                if(entry.key == enum_entry_key) {
                    return entry.value;
                }
            }

            return INVALID_VALUE;
        }
        public XmlEnumSet(){
            type = XML_DATA_TYPE_NAME.ENUM;
        }
    }
    public class XmlGroupSet : XmlBaseRefer{
        public XmlGroupSet() {
            type = XML_DATA_TYPE_NAME.GROUP;
        }
    }
    public class XmlSubClassSet : XmlBaseRefer{
        public XmlSubClassSet() {
            type = XML_DATA_TYPE_NAME.SUBCLASS;
        }
    }
    public class XmlClassSet : XmlSubClassSet {
        #region 序列化字段 
        [XmlElement(XML_ELEMENTS_NAME.DATASOURCE)]
        public List<XmlDataSource> DataSourceList = new List<XmlDataSource>();
        #endregion

        [XmlIgnore]
        public int TotalDataCount;  //级联表格中所有有效数据的行数
        [XmlIgnore]
        private Dictionary<string, string> m_primaryValCache = new Dictionary<string, string>();

        public override bool CheckAndAssemble(XmlMetalib parentLib) {
            if(!base.CheckAndAssemble(parentLib)) return false;

            foreach(var item in DataSourceList) {
                item.FormatName();
            }
            return true;
        }
        public bool CachePrimaryValue(string value, string debug_location_str) {
            m_primaryValCache.Add(value, debug_location_str);
            return true;
        }
        public bool CheckPrimaryUniqueness(string value, out string debug_str) {
            bool ret = m_primaryValCache.TryGetValue(value, out debug_str);
            return !ret;
        }

        public XmlClassSet() {
            type = XML_DATA_TYPE_NAME.CLASS;
        }
    }
    #endregion

    #region entry结构
    public abstract class XmlBaseEntry {
        [XmlAttribute(XML_ATTR_NAME.NAME)]
        public string name;
        [XmlAttribute(XML_ATTR_NAME.KEY)]
        public string key;

        #region 重组字段
        [XmlIgnore]
        public XmlBaseSet ParentSet;
        #endregion

        public virtual bool CheckAndAssemble(XmlBaseSet _p) {
            Reporter.SetEntryProgress(name);
            ParentSet = _p;
            return true;
        }
    }
    public class XmlFieldEntry : XmlBaseEntry{
        [XmlAttribute(XML_ATTR_NAME.TYPE)]
        public string type;
        [XmlAttribute(XML_ATTR_NAME.TYPE_PARAM)]
        public string type_param;
        [XmlAttribute(XML_ATTR_NAME.COUNT)]
        public string count_str;
        [XmlAttribute(XML_ATTR_NAME.VALID)]
        public int valid_rule_id;
        [XmlAttribute(XML_ATTR_NAME.DESC)]
        public string desc;
        [XmlAttribute(XML_ATTR_NAME.PRIMARY)]
        public string prime_str;
        [XmlAttribute(XML_ATTR_NAME.MODE)]
        public string mode_str;

        #region 重组装字段
        [XmlIgnore]
        public int count_num;
        [XmlIgnore]
        public bool count_ref_const = false; //count的字段配置，是否引用了常量配置
        [XmlIgnore]
        public bool Primary;
        [XmlIgnore]
        public JSON_MODE mode = JSON_MODE.COMMON;
        #endregion

        private bool tryParseCountAttr() {
            if(count_str == null) {
                //没有Count属性字段，则默认count = 1
                count_num = 1;
                return true;
            }

            if(int.TryParse(count_str, out count_num)) {
                //先尝试转换为int
                count_ref_const = false;
                return true; 
            }
            else if(ParentSet.ParentLib.TryGetConstValue(count_str, out count_num)) {
                //再尝试查找全局
                count_ref_const = true;
                return true;
            }
            Reporter.PushError("Count属性字段解析失败，请引用本Metalib中的const条目,或直接填写数字");
            return false;
        }
        public override bool CheckAndAssemble(XmlBaseSet _p) {
            if(!base.CheckAndAssemble(_p)) return false;

            if(!tryParseCountAttr()) return false;

            if(prime_str == "true") {
                if(count_num > 1) {
                    Reporter.PushError("主键entry不允许配置count字段");
                    return false;
                }
                Primary = true;
            }
            else {
                Primary = false;
            }

            if(ParentSet.type != XML_DATA_TYPE_NAME.CLASS && !string.IsNullOrEmpty(mode_str)) {
                Reporter.PushError("mode字段只支持classSet中的entry");
                return false;
            }
            if(mode_str == "client") {
                mode = JSON_MODE.CLIENT;
            }
            else if(mode_str == "server"){
                mode = JSON_MODE.SERVER;
            }

            return true;
        }
    }

    public class XmlEnumEntry : XmlBaseEntry {
        [XmlAttribute(XML_ATTR_NAME.VALUE)]
        public int value;
        public override bool CheckAndAssemble(XmlBaseSet _p) {
            if(!base.CheckAndAssemble(_p)) return false;

            return true;
        }
    }
    #endregion

    #region 有效性检查的配置
    public class XmlValidSet {
        [XmlElement(XML_ELEMENTS_NAME.REF)]
        public List<XmlValidEntry> validEntryList = new List<XmlValidEntry>();

        public bool CheckAndAssemble(XmlMetalib _p) {
            Reporter.SetSetProgress(XML_ELEMENTS_NAME.VALID);

            foreach(XmlValidEntry entry in validEntryList) {
                Reporter.SetEntryProgress(XML_ELEMENTS_NAME.REF);
                if(!_p.IfClassSetExists(entry.class_name)) {
                    Reporter.PushError("ClassName: {0}不存在！", entry.class_name);
                    return false;
                }
            }
            return true;
        }
    }
    public class XmlValidEntry {

        [XmlAttribute("class_name")]
        public string class_name;
        [XmlAttribute("sheet_name")]
        public string sheet_name;
        [XmlAttribute("column_name")]
        public string column_name;
        [XmlAttribute("ref_lib")]
        public string ref_metalibName;
        [XmlAttribute("ref_class")]
        public string ref_className;
        [XmlAttribute("ref_column")]
        public string ref_columnName;
    }
    #endregion
}

